package com.fy.fyspace.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fy.fyspace.common.manager.CosManager;
import com.fy.fyspace.common.manager.OssManager;
import com.fy.fyspace.common.result.PageResult;
import com.fy.fyspace.common.utils.DateFormatter;
import com.fy.fyspace.constant.KeysConstant;
import com.fy.fyspace.constant.ResultMessageConstant;
import com.fy.fyspace.ex.ConditionException;
import com.fy.fyspace.ex.handler.ExceptionHandler;
import com.fy.fyspace.mapper.FileInfoMapper;
import com.fy.fyspace.mapper.SpaceMapper;
import com.fy.fyspace.model.dto.file.FileQueryDTO;
import com.fy.fyspace.model.dto.file.RenameFileDTO;
import com.fy.fyspace.model.dto.file.UploadFileDTO;
import com.fy.fyspace.model.entity.FileInfo;
import com.fy.fyspace.model.entity.Space;
import com.fy.fyspace.model.enums.file.*;
import com.fy.fyspace.model.enums.space.SpaceTypeEnum;
import com.fy.fyspace.model.vo.file.FileStatisticsVO;
import com.fy.fyspace.model.vo.file.FolderVO;
import com.fy.fyspace.model.vo.file.PageResultData;
import com.fy.fyspace.model.vo.file.RecycleFileQueryVO;
import com.fy.fyspace.model.vo.user.UserSessionVO;
import com.fy.fyspace.service.FileInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.hutool.core.bean.BeanUtil.copyProperties;

@Slf4j
@Service
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private FileInfoMapper fileInfoMapper;

    @Autowired
    private CosManager cosManager;

    @Resource
    private HttpSession httpSession;

    @Resource
    private SpaceMapper spaceMapper;

    @Autowired
    private OssManager ossManager;

    /**
     * 上传文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadFile(UserSessionVO userSessionVO, UploadFileDTO uploadFileDTO) throws IOException {
        try {
            MultipartFile multipartFile = uploadFileDTO.getFile();
            String fileName = uploadFileDTO.getFileName();
            Long fileSize = uploadFileDTO.getFileSize();
            String fileMd5 = uploadFileDTO.getFileMd5();

            // 分片上传参数处理
            int chunkIndex = Integer.parseInt(uploadFileDTO.getChunkIndex());
            int chunks = Integer.parseInt(uploadFileDTO.getChunks());

            // 参数验证
            if (chunkIndex < 0 || chunks <= 0 || chunkIndex >= chunks) {
                throw new IllegalArgumentException("分片参数无效");
            }

            // 首片时检查空间
            if (chunkIndex == 0) {
                // 获取用户空间信息
                LambdaQueryWrapper<Space> wp = new LambdaQueryWrapper<>();
                wp.eq(Space::getUserId, userSessionVO.getId())
                  .eq(Space::getSpaceType, SpaceTypeEnum.PERSONAL.getSpaceType());
                Space userSpace = spaceMapper.selectOne(wp);
                
                if (userSpace == null) {
                    throw new ConditionException("用户空间不存在");
                }
                
                // 检查空间是否足够
                if (userSpace.getTotalSize() + fileSize > userSpace.getMaxSize()) {
                    throw new ConditionException(ResultMessageConstant.INSUFFICIENT_SPACE);
                }
                
                // 检查文件MD5，实现秒传
                if (fileMd5 != null && !fileMd5.isEmpty()) {
                    LambdaQueryWrapper<FileInfo> mdQuery = new LambdaQueryWrapper<>();
                    mdQuery.eq(FileInfo::getFileMd5, fileMd5)
                            .eq(FileInfo::getDelFlag, FileDelFlagEnums.USING.getFlag())
                            .eq(FileInfo::getFolderType, FileFolderTypeEnums.FILE.getType());
                    List<FileInfo> existFiles = fileInfoMapper.selectList(mdQuery);

                    if (!existFiles.isEmpty()) {
                        // 实现秒传
                        return handleQuickUpload(existFiles, userSessionVO.getId(), uploadFileDTO);
                    }
                }
            }

            // 生成新文件信息
            String fileExtension = getFileExtension(fileName);
            String objectName = userSessionVO.getUserName() + "ADD" + UUID.randomUUID().toString().substring(0, 6);
            String newObjectName = objectName + fileExtension;

            // 处理文件上传 - 使用阿里云OSS分片上传
            byte[] fileBytes = multipartFile.getBytes();
            List<String> uploadResult = ossManager.uploadAndMerge(
                    fileBytes,
                    fileName,
                    chunkIndex,
                    chunks,
                    uploadFileDTO.getFileId(),
                    newObjectName);

            // 处理返回结果
            if (uploadResult.get(0) != null) {
                // 还在上传中，返回uploadId
                return uploadResult.get(0);
            }

            // 如果上传完成，保存文件信息
            if (chunkIndex == chunks - 1) {
                FileInfo fileInfo = new FileInfo();
                fileInfo.setFileId(UUID.randomUUID().toString().replace("-", ""));
                fileInfo.setUserId(userSessionVO.getId());
                fileInfo.setFileName(fileName);
                fileInfo.setFilePid(uploadFileDTO.getFilePid());
                fileInfo.setFileSize(fileSize);
                fileInfo.setFileMd5(fileMd5);
                fileInfo.setFileCategory(FileCategoryEnums.getCategory(fileExtension));
                fileInfo.setFilePath(uploadResult.get(1));

                String extension = getFileExtension(fileName);
                fileInfo.setFileType(FileTypeEnums.getFileTypeBySuffix(extension).getType());
                fileInfo.setCreateTime(new Date());
                fileInfo.setLastUpdateTime(new Date());
                fileInfo.setFolderType(FileFolderTypeEnums.FILE.getType());
                fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
                fileInfo.setStatus(FileStatusEnums.USING.getStatus());

                // 设置文件类型和分类
                setFileTypeAndCategory(fileInfo, fileExtension);

                // 设置文件封面
                if (ArrayUtils.contains(FileTypeEnums.VIDEO.getSuffixs(), fileExtension.toLowerCase())) {
                    String coverUrl = uploadResult.get(1) + "?x-oss-process=video/snapshot,t_1000,f_jpg,w_800,h_600,m_fast";
                    fileInfo.setFileCover(coverUrl);
                } else if (ArrayUtils.contains(FileTypeEnums.IMAGE.getSuffixs(), fileExtension.toLowerCase())) {
                    fileInfo.setFileCover(uploadResult.get(1));
                } else {
                    fileInfo.setFileCover("");
                }

                fileInfoMapper.insert(fileInfo);
                return null;
            }

            return uploadResult.get(0);
        } catch (Exception e) {
            log.error("文件上传失败 - fileName: {}, chunkIndex: {}, chunks: {}", 
                    uploadFileDTO.getFileName(), uploadFileDTO.getChunkIndex(), uploadFileDTO.getChunks(), e);
            throw new ConditionException("文件上传失败");
        }
    }

    /**
     * 处理秒传
     */
    private String handleQuickUpload(List<FileInfo> existFiles, Long userId, UploadFileDTO uploadFileDTO) {
        FileInfo existFile = existFiles.get(0);
        
        // 检查当前用户是否已有该文件
        for (FileInfo file : existFiles) {
            if (file.getUserId().equals(userId) && file.getFilePid().equals(uploadFileDTO.getFilePid())) {
                log.info("文件已存在，实现秒传: {}", file.getFileName());
                return file.getFilePath();
            }
        }
        
        // 创建新的文件记录，复用存储信息
        FileInfo newFile = new FileInfo();
        newFile.setFileId(UUID.randomUUID().toString().replace("-", ""));
        newFile.setUserId(userId);
        newFile.setFileName(uploadFileDTO.getFileName());
        newFile.setFilePid(uploadFileDTO.getFilePid());
        newFile.setFileSize(existFile.getFileSize());
        newFile.setFileMd5(existFile.getFileMd5());
        newFile.setFilePath(existFile.getFilePath());
        newFile.setFileCover(existFile.getFileCover());
        newFile.setFileType(existFile.getFileType());
        newFile.setFileCategory(existFile.getFileCategory());
        newFile.setFolderType(FileFolderTypeEnums.FILE.getType());
        newFile.setDelFlag(FileDelFlagEnums.USING.getFlag());
        newFile.setStatus(FileStatusEnums.USING.getStatus());
        newFile.setCreateTime(new Date());
        newFile.setLastUpdateTime(new Date());
        
        fileInfoMapper.insert(newFile);
        log.info("文件秒传成功: {}", newFile.getFileName());
        
        return existFile.getFilePath();
    }

    /**
     * 设置文件类型和分类
     */
    private void setFileTypeAndCategory(FileInfo fileInfo, String fileExtension) {
        FileTypeEnums fileType = FileTypeEnums.getFileTypeBySuffix(fileExtension.toLowerCase());
        fileInfo.setFileType(fileType.getType());
        fileInfo.setFileCategory(FileCategoryEnums.getCategory(fileExtension));
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }
        int dotIndex = fileName.lastIndexOf(".");
        return dotIndex > 0 ? fileName.substring(dotIndex) : "";
    }

    /**
     * 分页查询
     */
    @Override
    public PageResult filePageQuery(FileQueryDTO fileQueryDTO, UserSessionVO userSessionVO) {
        // 1. 处理分页参数
        long pageSize = fileQueryDTO.getPageSize() != null ? Long.parseLong(fileQueryDTO.getPageSize()) : 15L;
        long pageNo = fileQueryDTO.getPageNo() != null ? Long.parseLong(fileQueryDTO.getPageNo()) : 1L;

        // 2. 创建分页对象
        Page<FileInfo> page = new Page<>(pageNo, pageSize);

        // 3. 构建查询条件
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getDelFlag, 2)
                .eq(FileInfo::getUserId, userSessionVO.getId());

        // 4. 添加文件分类查询条件
        if (fileQueryDTO.getFileCategory() != null) {
            queryWrapper.eq(FileInfo::getFileCategory, fileQueryDTO.getFileCategory());
        }

        // 5. 添加文件名模糊查询
        if (StringUtils.isNotBlank(fileQueryDTO.getFileNameFuzzy())) {
            queryWrapper.like(FileInfo::getFileName, fileQueryDTO.getFileNameFuzzy());
        }

        // 6.添加父文件夹id
        if (StringUtils.isNotBlank(fileQueryDTO.getFilePid())) {
            queryWrapper.eq(FileInfo::getFilePid, fileQueryDTO.getFilePid());
        }

        // 6. 添加排序
        queryWrapper.orderByDesc(FileInfo::getCreateTime);

        // 7. 执行查询
        fileInfoMapper.selectPage(page, queryWrapper);

        // 8. 转换查询结果
        List<PageResultData> resultList = page.getRecords().stream()
                .map(record -> {
                    PageResultData pageResultData = new PageResultData();

                    // 基本信息
                    pageResultData.setFileId(record.getFileId());
                    pageResultData.setUserName(userSessionVO.getUserName());
                    pageResultData.setFilePid(record.getFilePid());
                    pageResultData.setFileName(record.getFileName());
                    pageResultData.setFileCover(record.getFileCover());
                    pageResultData.setFilePath(record.getFilePath());
                    pageResultData.setFolderType(record.getFolderType());
                    pageResultData.setFileCategory(record.getFileCategory());
                    pageResultData.setFileType(record.getFileType());

                    // 文件大小格式化
                    pageResultData.setFileSize(formatFileSize(record.getFileSize()));

                    // 格式化时间
                    if (record.getCreateTime() != null) {
                        pageResultData.setCreateTime(DateFormatter.getYMDhmsFormatterStringByCST(
                                String.valueOf(record.getCreateTime())));
                    }
                    if (record.getLastUpdateTime() != null) {
                        pageResultData.setLastUpdateTime(DateFormatter.getYMDhmsFormatterStringByCST(
                                String.valueOf(record.getLastUpdateTime())));
                    }

                    return pageResultData;
                })
                .collect(Collectors.toList());

        // 9. 构建返回结果
        PageResult pageResult = new PageResult();
        pageResult.setTotalCount(page.getTotal());
        pageResult.setPageNo(page.getCurrent());
        pageResult.setPageSize(page.getSize());
        pageResult.setPageTotal(page.getPages());
        pageResult.setList(resultList);

        return pageResult;
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(Long size) {
        if (size == null || size < 0) return "0 B";

        if (size == 0) return "0 B";

        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = 0;

        try {
            // 避免size过大导致的计算错误
            double sizeDouble = size.doubleValue();
            while (sizeDouble >= 1024 && digitGroups < units.length - 1) {
                digitGroups++;
                sizeDouble = sizeDouble / 1024;
            }

            return String.format("%.2f %s", sizeDouble, units[digitGroups]);
        } catch (Exception e) {
            log.error("文件大小格式化失败", e);
            return size + " B";
        }
    }


    /**
     * 删除文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delFile(String fileIdList) {
        String[] strings = fileIdList.split(",");
        UserSessionVO userSessionVO = (UserSessionVO) httpSession.getAttribute(KeysConstant.LOGIN_SESSION_KEY);
        Long userId = userSessionVO.getId();
        for (String fileId : strings) {
            LambdaQueryWrapper<FileInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(FileInfo::getFileId, fileId)
                    .eq(FileInfo::getUserId, userId);
            FileInfo fileInfo = fileInfoMapper.selectList(lambdaQueryWrapper).get(0);
            ExceptionHandler.throwIf(fileInfo == null, ResultMessageConstant.NOT_YOUR);
            fileInfo.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
            fileInfo.setDelTime(new Date());
            fileInfo.setDelType(FileDelTypeEnums.DEL_HAND.getFlag());
            fileInfo.setLastUpdateTime(new Date());
            fileInfoMapper.updateById(fileInfo);
        }
    }

    /**
     * 重命名文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rename(RenameFileDTO renameFileDTO) {
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(renameFileDTO.getFileName());
        fileInfo.setLastUpdateTime(new Date());

        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileId, renameFileDTO.getFileId());

        fileInfoMapper.update(fileInfo, wrapper);
    }

    /**
     * 创建下载链接
     */
    @Override
    public String createDownloadURL(String fileId) {
        FileInfo fileInfo = fileInfoMapper.selectById(fileId);
        if (fileInfo == null) {
            throw new ConditionException(ResultMessageConstant.FILE_NOT_FOUND);
        }

        String redisKey = KeysConstant.LOGIN_SESSION_KEY + fileId;
        Map<String, String> downloadInfo = new HashMap<>();
        downloadInfo.put("fileName", fileInfo.getFileName());
        downloadInfo.put("filePath", fileInfo.getFilePath());

        String jsonStr = com.alibaba.fastjson.JSON.toJSONString(downloadInfo);
        redisTemplate.opsForValue().set(redisKey, jsonStr, 600, TimeUnit.SECONDS);

        return redisKey;
    }

    /**
     * 创建文件夹
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileInfo newFolder(String filePid, String fileName, UserSessionVO userSessionVO) {
        // 检查同一目录下是否存在同名文件夹
        LambdaQueryWrapper<FileInfo> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(FileInfo::getFilePid, filePid)
                .eq(FileInfo::getFileName, fileName)
                .eq(FileInfo::getFolderType, true)
                .eq(FileInfo::getDelFlag, 2)
                .eq(FileInfo::getUserId, userSessionVO.getId());

        if (fileInfoMapper.selectCount(checkWrapper) > 0) {
            throw new ConditionException("文件夹已存在");
        }

        FileInfo folder = new FileInfo();
        folder.setFileId(UUID.randomUUID().toString().replace("-", ""));
        folder.setUserId(userSessionVO.getId());
        folder.setFilePid(filePid);
        folder.setFileName(fileName);
        folder.setFolderType(FileFolderTypeEnums.FOLDER.getType());
        folder.setDelFlag(FileDelTypeEnums.USING.getFlag());
        folder.setCreateTime(new Date());
        folder.setLastUpdateTime(new Date());
        folder.setStatus(FileStatusEnums.USING.getStatus());

        fileInfoMapper.insert(folder);
        return folder;
    }

    /**
     * 获取文件夹信息
     */
    @Override
    public List<FolderVO> getFolderInfo(String fileIds) {
        List<FolderVO> folderVOList = new ArrayList<>();
        String[] fileIdArray = fileIds.split("/");

        for (String fileId : fileIdArray) {
            FileInfo fileInfo = fileInfoMapper.selectById(fileId);
            if (fileInfo != null) {
                FolderVO folderVO = new FolderVO();
                folderVO.setFileId(fileInfo.getFileId());
                folderVO.setFileName(fileInfo.getFileName());
                folderVOList.add(folderVO);
            }
        }

        return folderVOList;
    }

    /**
     * 获取所有文件夹
     */
    @Override
    public List<FileInfo> loadAllFolder(UserSessionVO userSessionVO, String filePid, String currentFileIds) {
        Long userId = userSessionVO.getId();

        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getUserId, userId)
                .eq(FileInfo::getFolderType, true)
                .eq(FileInfo::getDelFlag, 2);

        if (filePid != null) {
            queryWrapper.eq(FileInfo::getFilePid, filePid);
        }

        if (StringUtils.isNotBlank(currentFileIds)) {
            String[] fileIds = currentFileIds.split(",");
            queryWrapper.notIn(FileInfo::getFileId, Arrays.asList(fileIds));
        }

        queryWrapper.orderByDesc(FileInfo::getCreateTime);

        return fileInfoMapper.selectList(queryWrapper);
    }

    /**
     * 移动文件到指定文件夹
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeFileFolder(String fileIds, String filePid) {
        String[] fileIdArray = fileIds.split(",");
        for (String fileId : fileIdArray) {
            FileInfo fileInfo = fileInfoMapper.selectById(fileId);
            if (fileInfo != null) {
                fileInfo.setFilePid(filePid);
                fileInfo.setLastUpdateTime(new Date());
                fileInfoMapper.updateById(fileInfo);
            }
        }
    }

    /**
     * 获取文件路径
     */
    @Override
    public FileInfo getFilePath(String fileId) {
        return fileInfoMapper.selectById(fileId);
    }

    /**
     * 获取文件统计信息
     */
    @Override
    public FileStatisticsVO getFileStatistics(Integer id) {
        FileStatisticsVO statistics = new FileStatisticsVO();

        LambdaQueryWrapper<FileInfo> fileQuery = new LambdaQueryWrapper<>();
        fileQuery.eq(FileInfo::getUserId, id)
                .eq(FileInfo::getDelFlag, 2);
        statistics.setTotalFiles(fileInfoMapper.selectCount(fileQuery));

        LambdaQueryWrapper<FileInfo> todayQuery = new LambdaQueryWrapper<>();
        todayQuery.eq(FileInfo::getUserId, id)
                .eq(FileInfo::getDelFlag, 2)
                .apply("DATE(create_time) = CURDATE()");
        statistics.setTodayUploads(fileInfoMapper.selectCount(todayQuery));
        return statistics;
    }

    /**
     * 回收站文件分页查询
     */
    @Override
    public PageResult loadRecycleList(Integer pNo, Integer pSize, UserSessionVO userSessionVO) {
        // 处理分页参数
        long pageSize = pSize != null ? pSize : 15L;
        long pageNo = pNo != null ? pNo : 1L;

        // 创建分页对象
        Page<FileInfo> page = new Page<>(pageNo, pageSize);

        // 构建查询条件
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getDelFlag, FileDelFlagEnums.RECYCLE.getFlag())
                .eq(FileInfo::getUserId, userSessionVO.getId())
                .orderByDesc(FileInfo::getLastUpdateTime);

        // 执行查询
        fileInfoMapper.selectPage(page, queryWrapper);

        // 转换查询结果
        List<RecycleFileQueryVO> resultList = page.getRecords().stream()
                .map(record -> {
                    RecycleFileQueryVO recycleFileQueryVO = new RecycleFileQueryVO();
                    copyProperties(record, recycleFileQueryVO);
                    return recycleFileQueryVO;
                })
                .collect(Collectors.toList());

        // 构建返回结果
        PageResult pageResult = new PageResult();
        pageResult.setTotalCount(page.getTotal());
        pageResult.setPageNo(page.getCurrent());
        pageResult.setPageSize(page.getSize());
        pageResult.setPageTotal(page.getPages());
        pageResult.setList(resultList);

        return pageResult;
    }

    /**
     * 恢复删除文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recoverFile(List<String> fileIdList) {
        for (String fileId : fileIdList) {
            FileInfo fileInfo = fileInfoMapper.selectById(fileId);
            if (fileInfo != null) {
                fileInfo.setDelFlag(FileDelFlagEnums.USING.getFlag());
                fileInfo.setDelTime(null);
                fileInfo.setLastUpdateTime(new Date());
                fileInfoMapper.updateById(fileInfo);
                log.info("恢复文件成功 - fileId: {}, fileName: {}", fileId, fileInfo.getFileName());
            }
        }
    }

    /**
     * 永久删除回收站文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delRecycleFile(List<String> fileIdList, UserSessionVO userSessionVO) {
        try {
            for (String fileId : fileIdList) {
                FileInfo fileInfo = fileInfoMapper.selectById(fileId);
                if (fileInfo == null) {
                    continue;
                }

                if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
                    // 处理文件夹
                    deleteFolder(fileInfo, userSessionVO);
                } else {
                    // 处理文件
                    deleteFile(fileInfo, userSessionVO);
                }
            }

            // 更新用户空间使用量
            updateUserSpace(userSessionVO.getId());
        } catch (Exception e) {
            log.error("删除回收站文件失败", e);
            throw new RuntimeException("删除文件失败: " + e.getMessage());
        }
    }

    /**
     * 处理文件夹删除
     */
    private void deleteFolder(FileInfo folder, UserSessionVO userSessionVO) {
        // 更新文件夹状态
        folder.setDelFlag(FileDelFlagEnums.DEL.getFlag());
        folder.setLastUpdateTime(new Date());
        fileInfoMapper.updateById(folder);

        // 获取文件夹下所有内容
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFilePid, folder.getFileId())
                .eq(FileInfo::getUserId, userSessionVO.getId())
                .eq(FileInfo::getDelFlag, FileDelFlagEnums.RECYCLE.getFlag());

        List<FileInfo> subFiles = fileInfoMapper.selectList(wrapper);

        // 递归处理子内容
        for (FileInfo subFile : subFiles) {
            if (FileFolderTypeEnums.FOLDER.getType().equals(subFile.getFolderType())) {
                deleteFolder(subFile, userSessionVO);
            } else {
                deleteFile(subFile, userSessionVO);
            }
        }
    }

    /**
     * 处理文件删除
     */
    private void deleteFile(FileInfo file, UserSessionVO userSessionVO) {
        // 检查是否有其他用户在使用此文件
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileMd5, file.getFileMd5())
                .ne(FileInfo::getUserId, userSessionVO.getId())
                .eq(FileInfo::getDelFlag, FileDelFlagEnums.USING.getFlag());

        long otherUsersCount = fileInfoMapper.selectCount(wrapper);

        // 更新文件状态
        file.setDelFlag(FileDelFlagEnums.DEL.getFlag());
        file.setDelType(FileDelTypeEnums.DEL_HAND.getFlag());
        file.setDelTime(new Date());
        file.setLastUpdateTime(new Date());
        fileInfoMapper.updateById(file);

        // 如果没有其他用户使用，删除COS文件
        if (otherUsersCount == 0 && file.getFilePath() != null) {
            try {
                String key = file.getFilePath().substring(file.getFilePath().lastIndexOf("/") + 1);
                cosManager.deleteObject(key);
                log.info("删除COS文件成功 - key: {}", key);
            } catch (Exception e) {
                log.error("删除COS文件失败 - filePath: {}", file.getFilePath(), e);
            }
        }
    }

    /**
     * 更新用户空间使用量
     */
    private void updateUserSpace(Long userId) {
        // 获取用户空间信息
        LambdaQueryWrapper<Space> spaceWrapper = new LambdaQueryWrapper<>();
        spaceWrapper.eq(Space::getUserId, userId)
                .eq(Space::getSpaceType, SpaceTypeEnum.PERSONAL.getSpaceType());
        Space userSpace = spaceMapper.selectOne(spaceWrapper);

        if (userSpace == null) {
            throw new ConditionException("用户空间不存在");
        }

        // 计算用户当前使用的空间
        LambdaQueryWrapper<FileInfo> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileInfo::getUserId, userId)
                .eq(FileInfo::getDelFlag, FileDelFlagEnums.USING.getFlag())
                .select(FileInfo::getFileSize);

        List<FileInfo> files = fileInfoMapper.selectList(fileWrapper);
        long totalSize = files.stream()
                .mapToLong(FileInfo::getFileSize)
                .sum();

        // 更新空间使用量
        userSpace.setTotalSize(totalSize);
        spaceMapper.updateById(userSpace);
        log.info("更新用户空间使用量成功 - userId: {}, totalSize: {}", userId, totalSize);
    }

} 